﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Xml;
using ApiBetaSeries.Factories;

namespace ApiBetaSeries.Model
{
    /// <summary>
    /// Represent an Episode
    /// </summary>
    internal class Episode : ApiBetaSeries.IEpisode
    {
        /// <summary>
        /// Empty constructor
        /// </summary>
        public Episode() { }

        #region Attributes
        /// <summary>
        /// Title of the show
        /// </summary>
        public string Show { get; set; }
        /// <summary>
        /// Url of the show
        /// </summary>
        public string UrlShow { get; set; }
        /// <summary>
        /// Season of the episode
        /// </summary>
        public int Season { get; set; }

        /// <summary>
        /// Number of this episode
        /// </summary>
        public int Number { get; set; }
        /// <summary>
        /// Number of this episode : SxxExx
        /// </summary>
        public string NumberFormat { get; set; }
        /// <summary>
        /// Difusion date
        /// </summary>
        public DateTime Date { get; set; }
        /// <summary>
        /// Title of this episode
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// Description of this episode
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// Url of the picture for this episode
        /// </summary>
        public string Screen { get; set; }

        /// <summary>
        /// If the user has seen this episode
        /// </summary>
        public bool HasSeen { get; set; }


        private Bitmap m_screenBitmap = null;
        /// <summary>
        /// Picture for this episode
        /// </summary>
        public Bitmap ScreenBitmap
        {
            get
            {
                if (m_screenBitmap == null && !string.IsNullOrEmpty(Screen))
                {
                    m_screenBitmap = new Bitmap(Screen);
                }
                return m_screenBitmap;
            }
        }

        /// <summary>
        /// if the episode has been downloaded by the member
        /// </summary>
        public bool Downloaded { get; set; }

        /// <summary>
        /// Subtitle of the episode
        /// </summary>
        public List<ISubtitle> Subtitles { get; set; }

        /// <summary>
        /// Number of people who mark this episode
        /// </summary>
        public int NbMark { get; set; }

        /// <summary>
        /// Average mark of this episode
        /// </summary>
        public double AverageMark { get; set; }

        /// <summary>
        /// Mark the user give to this episode
        /// </summary>
        public int Mark { get; set; }

        #endregion Attributes

        #region inherits
        public override bool Equals(object obj)
        {
            if (obj == null) return false;

            if (this.GetType() != obj.GetType()) return false;

            Episode e = (Episode)obj;
            if (!Object.Equals(this.Show, e.Show)) return false;
            if (!Object.Equals(this.UrlShow, e.UrlShow)) return false;
            if (!Object.Equals(this.Season, e.Season)) return false;
            if (!Object.Equals(this.Number, e.Number)) return false;

            if (!Object.Equals(this.NumberFormat, e.NumberFormat)) return false;
            if (!Object.Equals(this.Date, e.Date)) return false;
            if (!Object.Equals(this.Title, e.Title)) return false;
            if (!Object.Equals(this.Description, e.Description)) return false;
            if (!Object.Equals(this.Screen, e.Screen)) return false;
            if (!Object.Equals(this.HasSeen, e.HasSeen)) return false;
            if (!Object.Equals(this.Downloaded, e.Downloaded)) return false;

            if (!Object.Equals(this.NbMark, e.NbMark)) return false;
            if (!Object.Equals(this.AverageMark, e.AverageMark)) return false;
            if (!Object.Equals(this.Mark, e.Mark)) return false;

            if (this.Subtitles == null)
            {
                if (e.Subtitles != null) return false;
                else return true;

            }

            if (this.Subtitles.Count != e.Subtitles.Count) return false;
            for (int i = 0; i < this.Subtitles.Count; ++i)
            {
                if (!Object.Equals(this.Subtitles[i], e.Subtitles[i])) return false;
            }

            // If we're here : everything's the same
            return true;
        }

        public override int GetHashCode()
        {
            return Show.GetHashCode() ^ Season.GetHashCode() ^ Number.GetHashCode();
        }

        public override string ToString()
        {
            return Show + " - " + NumberFormat + " - " + Title;
        }
        #endregion inherits

        #region Methods
        /// <summary>
        /// Mark the episode as watched on betaseries
        /// </summary>
        /// <param name="token">token of the member</param>
        /// <param name="note">note of the episode (default => none)</param>
        [ApiBetaSeries.Version.ApiMethod(false, "members/watched")]
        public void SetWatched(IUser user, int note = -1)
        {
            SetWatched(user.Token, note);
        }
        /// <summary>
        /// Mark the episode as watched on betaseries
        /// </summary>
        /// <param name="token">token of the member</param>
        /// <param name="note">note of the episode (default => none)</param>
        [ApiBetaSeries.Version.ApiMethod(true, "members/watched")]
        public void SetWatched(string token, int note = -1)
        {
            string url = string.Format("/members/watched/{0}.xml", this.UrlShow);
            string param = string.Format("&token={0}&season={1}&episode={2}", token, this.Season, this.Number);
            if (note >= 0)
                param += "&note=" + note;

            XmlDocument doc = Utils.UtilsXML.GetUrl(url, param);
            this.HasSeen = true;
        }

        /// <summary>
        /// Mark the episode as downloaded for the member
        /// </summary>
        /// <param name="user">Member who has watched the episode</param>
        [ApiBetaSeries.Version.ApiMethod(false, "members/downloaded")]
        public bool SetDownloaded(IUser user)
        {
            return SetDownloaded(user.Token);
        }
        /// <summary>
        /// Mark the episode as downloaded or not
        /// </summary>
        /// <param name="token">token of the member</param>
        /// <returns>if the episode is download or not</returns>
        [ApiBetaSeries.Version.ApiMethod(true, "members/downloaded")]
        public bool SetDownloaded(string token)
        {
            string url = string.Format("/members/downloaded/{0}.xml", this.UrlShow);
            string param = string.Format("&token={0}&season={1}&episode={2}", token, this.Season, this.Number);

            XmlDocument doc = Utils.UtilsXML.GetUrl(url, param);

            this.Downloaded = Utils.UtilsXML.GetBoolValue(doc["root"], "downloaded");
            return this.Downloaded;
        }

        /// <summary>
        /// Defined a mark for this episode
        /// </summary>
        /// <param name="user">the member who marks this episode</param>
        /// <param name="mark">mark of this episode</param>
        [ApiBetaSeries.Version.ApiMethod(false, "members/note")]
        public void SetMark(IUser user, int mark)
        {
            SetMark(user.Token, mark);
        }

        /// <summary>
        /// Defined a mark for this episode
        /// </summary>
        /// <param name="user">token of an identified member</param>
        /// <param name="mark">mark of this episode</param>
        [ApiBetaSeries.Version.ApiMethod(true, "members/note")]
        public void SetMark(string token, int mark)
        {
            string url = string.Format("/members/note/{0}.xml", this.UrlShow);
            string param = string.Format("&token={0}&season={1}&episode={2}&note={3}", token, this.Season, this.Number, mark);

            XmlDocument doc = Utils.UtilsXML.GetUrl(url, param);
            this.Mark = mark;
        }

        /// <summary>
        /// Get all the subtitles for the episode
        /// </summary>
        /// <param name="type">VO/VF/VOVF</param>
        /// <returns>List of subtitles</returns>
        [ApiBetaSeries.Version.ApiMethod(true, "subtitles/show")]
        public List<ISubtitle> GetSubtitles(SubtitleLanguage type = SubtitleLanguage.VOVF)
        {
            List<ISubtitle> list = new List<ISubtitle>();
            if (type == SubtitleLanguage.Other)
            {
                throw new ArgumentException("Cannot use SubtitleLanguage : Other for this request");
            }
            string stype = type.ToString();

            XmlDocument doc = Utils.UtilsXML.GetUrl("/subtitles/show/" + this.UrlShow + ".xml", "&season=" + this.Season + "&episode=" + this.Number + "&language=" + stype);
            XmlElement xe = doc["root"]["subtitles"];

            if (xe == null)
            {
                throw new BetaSeriesException(1003, "Invalid action.");
            }
            foreach (XmlElement sub in xe.GetElementsByTagName("subtitle"))
            {
                ISubtitle s = SubtitleFactory.CreateSubtitle(sub);
                list.Add(s);
            }

            return list;
        }
        #endregion Methods
    }
}
